package util

import "sync"

type BlockingQueue[T any] struct {
	inner []T
	lock  *sync.Mutex
	cond  *sync.Cond
}

func NewBlockingQueue[T any]() *BlockingQueue[T] {
	l := sync.Mutex{}
	c := sync.NewCond(&l)
	return &BlockingQueue[T]{
		inner: make([]T, 0),
		lock:  &l,
		cond:  c,
	}
}

func (b *BlockingQueue[T]) Append(t T) {
	b.lock.Lock()
	defer b.lock.Unlock()
	b.inner = append(b.inner, t)
	b.cond.Signal()
}

func (b *BlockingQueue[T]) Pop() T {
	var t T
	b.lock.Lock()
	defer b.lock.Unlock()
	for len(b.inner) == 0 {
		b.cond.Wait()
	}
	t = b.inner[len(b.inner)-1]
	b.inner = b.inner[:len(b.inner)-1]
	return t
}
